import { Io } from "../object/extendOwn"
import { isArrayLike } from "./each"
import { optimizeCb } from "../util/iteratee"

//创建一个向左或向右迭代的归约函数。
export const createReduce = function (dir) {
  //在单独的函数中包装将参数变量重新分配的代码
  //访问`arguments.length`以避免性能下降的代码。 （＃1991）
  var reducer = function <T, R>(obj: Io, iteratee: (memo, value, keys, obj?) => R, memo: R, initial) {
    const keys = !isArrayLike(obj) && Object.keys(obj)
    const length = (keys || obj).length
    let index = dir > 0 ? 0 : length - 1
    if (!initial) {
      memo = obj[keys ? keys[index] : index]
      index += dir
    }
    for (; index >= 0 && index < length; index += dir) {
      var currentKey = keys ? keys[index] : index
      memo = iteratee(memo, obj[currentKey], currentKey, obj)
    }
    return memo;
  }
  return function <T, R>(obj: Io, iteratee: (a: T, b: T) => R, memo?: string | number, context?) {
    var initial = arguments.length >= 3
    return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial)
  }
}


//别名为 inject 和 foldl, reduce方法把list中元素归结为一个单独的数值。Memo是reduce函数的初始值，会被每一次成功调用iteratee函数的返回值所取代 。这个迭代传递4个参数：memo,value 和 迭代的index（或者 key）和最后一个引用的整个 list。
//如果没有memo传递给reduce的初始调用，iteratee不会被列表中的第一个元素调用。第一个元素将取代memo参数传递给列表中下一个元素调用的iteratee函数。
// var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
// => 6
const reduce = createReduce(1)

export default reduce
export const reduceRight = createReduce(0)

// reduce<string, string>({ a: 1, b: 2 }, (a, b) => a + b, 0)

